/*! \file	tools.hpp
 *  \brief	Declarations for generic tools not depending on libraries such as OpenCV, PCL and ROS.
*/

#ifndef _THERMALVIS_TOOLS_H_
#define _THERMALVIS_TOOLS_H_

/***** General includes *****/
//#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <iostream>
#include <fstream>
#include <sys/stat.h>
#include <dirent.h>
#include <sstream>
#include <string>
#include <string.h>
#include <assert.h>
#include <fcntl.h>              /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

// Standard
//#include <stdlib.h>
#include <cstdlib>
#include <stdio.h>
// #include <math.h>
#include <cmath>
#include <iostream>
#include <fstream>
#include <limits.h>

#ifndef _WIN32
// Linux
#include <unistd.h>
#include <getopt.h>

// Miscellaneous
#include <sys/stat.h>
#include <dirent.h>
#endif

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>

//#include "opencv_resources.hpp"
#include "sys/time.h"

#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/gpu/gpu.hpp"
#include <opencv2/video/video.hpp>

#define USE_CLAHE 0

using namespace std;
//using namespace cv;

typedef std::pair<unsigned int,unsigned int> mypair;
bool comparator ( const mypair& l, const mypair& r);

/// \brief      Counts and returns a list of all specified elements within a folder
int countElementsInFolder(const char* folderName, vector<string>& elementNames, int elementType);

void convertUcharToBinary(unsigned char val, int* binaryArray);

double lookupValue(double xi, double yi, double maxVal, const cv::Mat& lookupMat);

double getInterpolatedVal(const cv::Mat& img, cv::Point2f& coord);

/// \brief      Distance between two 3D points in double format
double distBetweenPts(cv::Point3d& P1, cv::Point3d& P2);

/// \brief      Calculate the mean and standard deviation of a vector of doubles
void calcParameters(const vector<double>& v, double& mean, double& stdev);

/// \brief      Calculates perpendicular distance between two "parallel" lines
double calcLinePerpDistance(double *line1, double *line2);

void findLinearModel(double* x, double* y, int termsToConsider, double &m, double &c);

/// \brief      Calculates time elapsed since the last time the timer was reset
double timeElapsedMS(struct timeval& timer, bool reset = true);

bool matricesAreEqual(cv::Mat& mat1, cv::Mat& mat2);
cv::Scalar getRandomColour();

void addUniqueToVector(vector<unsigned int>& dst, vector<unsigned int>& src);

double asymmetricGaussianValue(double score, double mean, double loVar, double hiVar);

void randomSelection(vector<unsigned int>& src, vector<unsigned int>& dst, unsigned int max);

/// \brief 		Calculates the perpindicular distance between a line (P1 to P2) and a point (P3)
double perpDist(cv::Point2f& P1, cv::Point2f& P2, cv::Point2f& P3);

/// \brief      Redistorts points using an established distortion model
void redistortPoints(const vector<cv::Point2f>& src, vector<cv::Point2f>& dst, const cv::Mat& cameraMatrix, const cv::Mat& distCoeffs, const cv::Mat& newCamMat=cv::Mat::eye(3,3,CV_64FC1));

/// \brief		Calculates Factorial of an integer
long long int factorial(int num);

/// \brief 		Calculates the distance between two "Point" points
double distBetweenPts(cv::Point& P1, cv::Point& P2);
/// \brief      Calculates the distance between two "Point2f" points
double distBetweenPts2f(cv::Point2f& P1, cv::Point2f& P2);

/// \brief      Gets next possible combination for an exhaustive combinatorial search
void getNextCombo(vector<unsigned int>& currentIndices, int r, int n);

/// \brief      Selects the score which is minimally better than a specified proportion of all scores
double findEquivalentProbabilityScore(double* values, int quantity, double prob);

void readPoints(const char *filename, vector<cv::Point2f>& pts);
void writePoints(const char *filename, const vector<cv::Point2f>& pts);

/// \brief      Converts a raw byte as an 8-bit character array of 1s and 0s
void convert_byte_to_binary_string(void* src, char* dst);

/// \brief 		Generates a point that's half way in between the two input points
cv::Point2f meanPoint(cv::Point2f& P1, cv::Point2f& P2);

/// \brief      Finds the minimum separation between any two points in a set
double findMinimumSeparation(vector<cv::Point2f>& pts);

#endif
